package com.sdy.sso.web.controller;

import com.sdy.auth.api.AuthApi;
import com.sdy.auth.api.model.UserInfo;
import com.sdy.auth.client.config.SsoConfig;
import com.sdy.auth.client.service.SsoService;
import com.sdy.common.constant.Constants;
import com.sdy.common.model.Response;
import com.sdy.common.model.Result;
import com.sdy.common.utils.Assert;
import com.sdy.common.utils.DateUtil;
import com.sdy.common.utils.EncodeUtil;
import com.sdy.common.utils.RandomUtil;
import com.sdy.common.utils.StringUtil;
import com.sdy.mq.service.MqProducerService;
import com.sdy.mvc.utils.CookieUtil;
import com.sdy.mvc.utils.HttpUtil;
import com.sdy.redis.service.RedisService;
import com.sdy.sso.biz.constants.MqConstants;
import com.sdy.sso.biz.constants.RedisConstants;
import com.sdy.usercenter.api.UserQueryApi;
import com.sdy.usercenter.api.dto.DeptDto;
import com.sdy.usercenter.api.dto.UserDTO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.security.KeyPair;
import java.util.Base64;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

/**
 * <p>File: LoginController.java</p>
 * <p>Description: LoginController</p>
 *
 * @author zzq
 * @version V1.0
 * @since 2019-05-09
 */
@Slf4j
@Controller
@RequestMapping("/login")
public class LoginController {
    @Autowired
    private RedisService redisService;
    @Autowired
    private MqProducerService mqProducerService;
    @Autowired
    private AuthApi authApi;
    @Value("${res.app.raw.code:}")
    private String appRawCode;
    @Autowired
    private UserQueryApi userQueryApi;
    @Autowired
    private SsoService ssoService;
    
    private static Map<String, String> pageMap = new HashMap<>();
    
    static {
        pageMap.put("dataQuery", "/page/login/login-dataquery");
        pageMap.put("data-exchange", "/page/login/login-dataexchange");
    }

    @RequestMapping("/page")
    public String loginPage(HttpServletRequest request, Model model) throws Exception {
        String targetUrl = request.getParameter("targetUrl");
        model.addAttribute("targetUrl", targetUrl);
        String appcode = request.getParameter("appcode");
        model.addAttribute("appCode", appcode);
        Integer userId = ssoService.getUserId(request);
        if (userId != null) {
            if (StringUtil.isBlank(targetUrl)) {
                return "redirect:/";
            }
            String token = CookieUtil.getCookie(request, "token");
            String randomStr = generateLoginTokenEncodeStr(token);
            return "redirect:" + HttpUtil.appendUrlParam(targetUrl, "token_enc", randomStr);
        }
        return pageMap.computeIfAbsent(appcode, code -> pageMap.getOrDefault(appRawCode, "/page/login/login"));
    }
    
    private String generateLoginTokenEncodeStr(String token) throws Exception {
        Assert.isBlank(token, "登录信息已失效，请刷新页面！");
        KeyPair keyPair = EncodeUtil.rsaGenKeyPair();
        byte[] encryptedBytes=EncodeUtil.rsaEncrypt(token.getBytes(), keyPair.getPublic());
        String base64Token = EncodeUtil.bytesToHexString(encryptedBytes);
        String randomStr = RandomUtil.produceStringAndNumber(32);
        redisService.set(RedisConstants.REDIS_PREFIX + "token_" + randomStr, base64Token, 180);
        redisService.set(RedisConstants.REDIS_PREFIX + "privateKey_:" + randomStr,
                Base64.getEncoder().encodeToString(keyPair.getPrivate().getEncoded()), 20);
        return randomStr;
    }

    /**
     * 部门数据
     */
    @GetMapping("/listDept")
    @ResponseBody
    public Response listDept(String keyword) {
        List<DeptDto> deptList = userQueryApi.listDept(keyword);
        return Response.success(deptList);
    }

    /**
     * 子部门数据
     */
    @GetMapping("/listSubDept")
    @ResponseBody
    public Response listSubDept(Integer parentId) {
        List<DeptDto> children = userQueryApi.listDept(parentId);
        return Response.success(children);
    }

    @PostMapping("/confirm")
    @ResponseBody
    public Response confirm(HttpServletRequest request, HttpServletResponse response) throws Exception {
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        String targetUrl = request.getParameter("targetUrl");
        String appCode = request.getParameter("appCode");
        String deptId = request.getParameter("deptId");
        Assert.isBlank(deptId, "请选择部门");
        if ("/".equals(targetUrl)) {
            targetUrl = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort();
        }
        Result<UserInfo> result = authApi.login(
                username,
                Integer.valueOf(deptId),
                password,
                (String) request.getSession().getAttribute(Constants.LOGIN_TOKEN),
                HttpUtil.getIpAddr(request)
        );
        if (result.getSuccess()) {
            Response r = authApi.checkAuthorization(result.getData().getUserId(), "_______", appCode);
            if (Boolean.FALSE.equals(r.getData())) {
                return Response.error("用户没有登录该系统的权限。");
            }
        } else {
            return Response.error(result.getMessage(), result.getCode());
        }
        String token = UUID.randomUUID().toString();
        CookieUtil.setCookie(response, "token", token, true);
        UserInfo userInfo = result.getData();
        redisService.set(token, userInfo, SsoConfig.SESSION_SECOND_OUT);
        mqProducerService.send(MqConstants.Tags.TAG_OP_LOG,
                "0".concat(MqConstants.SEP_TOKEN)
                        .concat(userInfo.getUserId().toString()).concat(MqConstants.SEP_TOKEN)
                        .concat(DateUtil.formatTime(new Date())).concat(MqConstants.SEP_TOKEN)
                        .concat(HttpUtil.getIpAddr(request)).concat(MqConstants.SEP_TOKEN)
                        .concat(userInfo.getUserName() + " 登录系统：" + targetUrl)
        );
        String randomStr = generateLoginTokenEncodeStr(token);
        return Response.success(randomStr);
    }

    /**
     * 登录页token
     * @param request
     * @return
     */
    @GetMapping("/token")
    @ResponseBody
    public Response token(HttpServletRequest request) {
        String token = RandomUtil.produceString(10);
        request.getSession().setAttribute(Constants.LOGIN_TOKEN, token);
        return Response.success(token);
    }
}
